// xmemory internal header (from <memory>) -*-c++-*-
// Copyright 2003-2010 IAR Systems AB. 
#ifndef _XMEMORY_
#define _XMEMORY_

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <cstdlib>
#include <new>
#include <xutility>
#include <iutility>

#define _CPOINTER_X(T, A)               \
        typename A::template rebind<T>::other::const_pointer
#define _CREFERENCE_X(T, A)     \
        typename A::template rebind<T>::other::const_reference
#define _POINTER_X(T, A)        \
        typename A::template rebind<T>::other::pointer
#define _REFERENCE_X(T, A)      \
        typename A::template rebind<T>::other::reference
#define _SIZE_TYPE_X(T, A)      \
        typename A::template rebind<T>::other::size_type

_STD_BEGIN

// Declare all variants of the allocation and deallocation functions.
  template<typename _Ty> struct _Allocator;
#define __HEAP_MEM_HELPER1__(mem, i)                                           \
  template<> struct _Allocator<void mem>                                       \
  {                                                                            \
    static void mem * allocate(                                                \
                           _TypeUtil::_PointerInfo<void mem *>::_SizeType _Sz) \
    {                                                                          \
      return operator new mem(_Sz);                                            \
    }                                                                          \
    static void deallocate(void mem * _Ptr)                                    \
    {                                                                          \
      operator delete(_Ptr);                                                   \
    }                                                                          \
  };
#pragma language = save
#pragma language = extended
__HEAP_MEMORY_LIST1__()
#undef __HEAP_MEM_HELPER1__
#pragma language = restore

// Implement the default variants of allocation and deallocation
template<> struct _Allocator<void>
{
  static void * allocate(_TypeUtil::_PointerInfo<void *>::_SizeType _Sz)
  {
    return operator new(_Sz);
  }
  static void deallocate(void * _Ptr)
  {
    operator delete(_Ptr);
  }
};

// TEMPLATE FUNCTION _Construct
#pragma basic_template_matching
template<class _T1,
  class _T2> inline
void _Construct(_T1 *_Ptr, const _T2& _Val)
{       // construct object at _Ptr with value _Val
  typedef typename _TypeUtil::_CopyMemory<_T1, void>::_Type _Void_type;
  new ((_Void_type *)_Ptr) _T1(_Val); 
}

// TEMPLATE FUNCTION _Construct
template<class _T1,
  class _T2> inline
void _Construct(const _T1 *const *_Ptr, const _T2 *_Val)
{       // construct pointer object at _Ptr with value _Val
  _Ptr = _T1(_Val);
}

// TEMPLATE FUNCTION _Destroy
template<class _Ty> inline
void _Destroy(_Ty *_Ptr)
{       // destroy object at _Ptr
  _DESTRUCTOR(_Ty, _Ptr); 
}

template<> inline
void _Destroy(char *)
{}      // destroy a char (do nothing)

template<> inline
void _Destroy(wchar_t *)
{}      // destroy a wchar_t (do nothing)

#pragma basic_template_matching
template<typename _T1, typename _T2>
inline
void _ReAssign(_T1 *_Ptr, const _T2& _Val)
{
  _Destroy(_Ptr);
  _Construct(_Ptr, _Val);
}

// TEMPLATE CLASS _Allocator_base
template<class _Ty>
struct _Allocator_base
{       // base class for generic allocators
  typedef _Ty value_type;
};

// TEMPLATE CLASS _Allocator_base<const _Ty>
template<class _Ty>
struct _Allocator_base<const _Ty>
{       // base class for generic allocators for const _Ty
  typedef _Ty value_type;
};

// TEMPLATE CLASS allocator
template<class _Ty>
class allocator
  : public _Allocator_base<_Ty>
{       // generic allocator for objects of class _Ty
  typedef typename _TypeUtil::_CopyMemory<_Ty, void>::_Type _Void_type;
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;
public:
  typedef _Allocator_base<_Ty> _Mybase;
  typedef typename _Mybase::value_type value_type;
  typedef value_type *pointer;
  typedef value_type& reference;
  typedef const value_type *const_pointer;
  typedef const value_type& const_reference;
  typedef typename _TypeUtil::_PointerInfo<pointer>::_SizeType size_type;
  typedef typename _TypeUtil::_PointerInfo<pointer>::_IndexType difference_type;

  template<class _Other>
  struct rebind
  {     // convert an allocator<_Ty> to an allocator <_Other>
    typedef allocator<_Other> other;
  };

  pointer address(reference _Val) const
  {     // return address of mutable _Val
    return (&_Val); 
  }

  const_pointer address(const_reference _Val) const
  {     // return address of nonmutable _Val
    return (&_Val); 
  }

  allocator()
  {}    // construct default allocator (do nothing)

  allocator(const allocator<_Ty>&)
  {}    // construct by copying (do nothing)

  template<class _Other>
  allocator(const allocator<_Other>&)
  {}    // construct from a related allocator (do nothing)

  template<class _Other>
  allocator<_Ty>& operator=(const allocator<_Other>&)
  {     // assign from a related allocator (do nothing)
    return (*this); 
  }

  void deallocate(pointer _Ptr, size_type)
  {     // deallocate object at _Ptr, ignore size
    _Allocator<_Void_type>::deallocate(_Ptr); 
  }

  pointer allocate(size_type _Count)
  {     // allocate array of _Count elements
    return (pointer)_Allocator<_Void_type>::allocate(_Count * sizeof(_Ty));
  }

  pointer allocate(size_type _Count, const void *)
  {     // allocate array of _Count elements, ignore hint
    return (allocate(_Count)); 
  }

  void construct(pointer _Ptr, _ParamTy _Val)
  {     // construct object at _Ptr with value _Val
    _Construct(_Ptr, _Val); 
  }
  // Provide a template implementation as well, to make it possible to
  // call other constructors than the copy constructor.
  template<typename _Ty2>
  void construct(pointer _Ptr, _Ty2 const & _Val)
  {     // construct object at _Ptr with value _Val
    _Construct(_Ptr, _Val); 
  }

  void destroy(pointer _Ptr)
  {     // destroy object at _Ptr
    _Destroy(_Ptr); 
  }

  size_type max_size() const
  {     // estimate maximum array size
    size_type _Count = (size_type)(-1) / sizeof (_Ty);
    return (0 < _Count ? _Count : 1); 
  }
};

// allocator TEMPLATE OPERATORS
template<class _Ty,
  class _Other> inline
bool operator==(const allocator<_Ty>&, const allocator<_Other>&)
{       // test for allocator equality (always true)
  return (true); 
}

template<class _Ty,
  class _Other> inline
bool operator!=(const allocator<_Ty>&, const allocator<_Other>&)
{       // test for allocator inequality (always false)
  return (false); 
}

// CLASS allocator<void>
#define _VOID_ALLOCATOR(mem)                                     \
  template<> class allocator<void mem>                           \
  {       /* generic allocator for type void */                  \
  public:                                                        \
    typedef void mem _Ty;                                        \
    typedef _Ty *pointer;                                        \
    typedef const _Ty *const_pointer;                            \
    typedef _Ty value_type;                                      \
                                                                 \
    template<class _Other>                                       \
    struct rebind                                                \
    {       /* convert an allocator<void> to an allocator <_Other>*/\
      typedef allocator<_Other> other;                           \
    };                                                           \
                                                                 \
    allocator()                                                  \
    {}      /* construct default allocator (do nothing) */       \
                                                                 \
    allocator(const allocator<_Ty>&)                             \
    {}      /* construct by copying (do nothing) */              \
                                                                 \
    template<class _Other>                                       \
    allocator(const allocator<_Other>&)                          \
    {}      /* construct from related allocator (do nothing) */  \
                                                                 \
    template<class _Other>                                       \
    allocator<_Ty>& operator=(const allocator<_Other>&)          \
    {       /* assign from a related allocator (do nothing) */   \
      return (*this);                                            \
    }                                                            \
  };

_VOID_ALLOCATOR()
#pragma language = save
#pragma language = extended
#define __DATA_PTR_MEM_HELPER1__(mem, i) _VOID_ALLOCATOR(mem)
__DATA_PTR_MEMORY_LIST1__()
#undef __DATA_PTR_MEM_HELPER1__
#pragma language = restore

// Detect if a type is an instantiation of the standard allocator
template<typename _Ty>
struct _IsStdAlloc0
{
  enum { _Result = false };
};

template<typename _Ty>
struct _IsStdAlloc0< allocator<_Ty> >
{
  enum { _Result = true };
};

template<typename _Ty>
struct _IsStdAlloc
{
  enum { _Result = _IsStdAlloc0<typename _TypeUtil::_StripMemory<_Ty>::_Type>::_Result };
};

// TEMPLATE FUNCTION _Destroy_range
#pragma basic_template_matching
template<class _Ty,
  class _Alloc> inline
void _Destroy_range(_Ty *_First, _Ty *_Last, _Alloc& _Al)
{       // destroy [_First, _Last)
  if (__has_destructor(*_First))
  {
  for (; _First != _Last; ++_First)
    _Al.destroy(_First); 
}
}

_STD_END
#endif /* _XMEMORY_ */

/*
 * This file is derived from software bearing the following
 * restrictions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Permission to use, copy, modify, distribute and sell this
 * software and its documentation for any purpose is hereby
 * granted without fee, provided that the above copyright notice
 * appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation.
 * Hewlett-Packard Company makes no representations about the
 * suitability of this software for any purpose. It is provided
 * "as is" without express or implied warranty.
 */

/*
 * Copyright (c) 1992-2009 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
 V5.04:0576 */
